﻿using System;
using System.Linq;
using CardPlay.Model.ActionModel;
using CardPlay.Model.GameModel;
using CardPlay.Model.GameModel.Actions;

namespace CardPlay.DemoPack.Games.FortyThievesVariants
{
    [Game("61C57C1D-E37D-4C93-8060-F03BF26A1041", LevelOfDifficulty.Easy, LevelOfSkill.MostlyChance, DurationOfPlay.MoreThan10Minutes, Family = FamilyName)]
    public class Cruel : FortyThieves
    {
        public Cruel()
        {
            TotalDecks = 1;
            TotalFoundations = 4;
            TotalTableaus = 12;
            TableauDealFormat = "4 up";
            MaximumDeals = 1;
            DealFoundationsInSetup = true;
            PreprocessAction = AugmentMovePileAction;
        }

        protected override IAction QueryActionAt(PartLocation location)
        {
            return location.Matches(Stock)
                ? (IsRedealPossible ? CreateRedealAction() : null)
                : base.QueryActionAt(location);
        }

        protected override bool AllowedToBuildEmptyTableau(MovePileAction action)
        {
            return false;
        }

        protected virtual IAction CreateResetStockAction()
        {
            return null;
        }

        private IAction CreateRedealAction()
        {
            var action = new ComplexAction();

            var topOfStock = new PartLocation(Stock, 0);

            foreach (var pile in PilesNamed(AnyTableau).Where(pile => !pile.IsEmpty).Reverse())
            {
                action.Add(new GatherPileAction(this, new PartLocation(pile.Name, 0), topOfStock));
                topOfStock.Index += pile.Count;
            }

            var resetStockAction = CreateResetStockAction();
            if (resetStockAction != null) action.Add(resetStockAction);

            foreach (var pile in PilesNamed(AnyTableau).TakeWhile(pile => topOfStock.Index > 0))
            {
                topOfStock.Index = Math.Max(0, topOfStock.Index - 4);
                action.Add(new GatherPileAction(this, topOfStock, new PartLocation(pile.Name, 0)));
            }

            action.Add(new IncrementDealCountAction(this));

            return action;
        }

        private IAction AugmentMovePileAction(IAction action)
        {
            var movePileAction = action as MovePileAction;
            return movePileAction == null
                ? action
                : new ComplexAction { action, new ResetDealCountAction(this) };
        }
    }
}